AWS SDK で使用する IAM ロールのポリシーを変更したのに権限エラーとなるときの対処方法
困っていた内容
AWS SDK を使用し、プログラムから AWS サービスへアクセスしようとしたところ、Access Denied に関するエラーが出力されます。
EC2 インスタンスにアタッチした IAM ロールのポリシーでは、対象サービスのアクセスを許可しましたが、なぜ権限エラーが出るのでしょうか?
どう対応すればいいの?
以下の順番に設定やソースコードが正しいか確認してください。
- エラーメッセージに原因が書かれていたらその内容を調べる
- VPC のリソースにアクセスしようとした場合、セキュリティグループやネットワーク ACL、ファイアウォールで通信が許可されているか調べる
- 対象サービス側でポリシーが設定できる場合、ポリシーで IAM ロールのアクセスが許可されているか調べる(S3 バケットポリシーなど)
- AWS SDK の認証情報が IAM ロールから取得しているか調べる
AWS SDK(AWS CLI はこちら)は認証情報を取得する順序が決まっています。たとえば AWS SDK for Java の場合、デフォルトの認証情報プロバイダチェーン DefaultAWSCredentialsProviderChain
は次の順序で認証情報を取得します。
AWS 認証情報の使用 - AWS SDK for Java
- 環境変数–
AWS_ACCESS_KEY_ID
とAWS_SECRET_ACCESS_KEY
AWS SDK for JavaはEnvironmentVariableCredentialsProviderクラスを使用してこれらの認証情報を読み込みます。- Java –
aws.accessKeyId
のシステムプロパティとaws.secretKey
AWS SDK for Javaは SystemPropertiesCredentialsProviderを使用してこれらの認証情報を読み込みます。- 環境またはコンテナからのウェブアイデンティティトークンの認証情報。
- 通常、デフォルトの認証情報プロファイルファイル (この場所はプラットフォームによって異なる場合があります) にあり、多くの AWS –と AWS CLI によって共有されます。
~/.aws/credentials
SDKsAWS SDK for Javaは ProfileCredentialsProviderを使用してこれらの認証情報を読み込みます。
AWS CLI によって提供される aws configure コマンドを使用して、認証情報ファイルを作成できます。または、テキストエディタでファイルを編集して作成できます。認証情報ファイル形式に関する情報については、「AWS 認証情報のファイル形式」を参照してください。- Amazon ECS コンテナの認証情報 – 環境変数
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
が設定されている場合に、Amazon ECS から読み込まれます。AWS SDK for Javaは ContainerCredentialsProviderを使用してこれらの認証情報を読み込みます。この値の IP アドレスを指定できます。- インスタンスプロファイル認証情報 – EC2 インスタンスで使用され、Amazon EC2 メタデータサービスによって提供されます。AWS SDK for Javaは InstanceProfileCredentialsProviderを使用してこれらの認証情報を読み込みます。この値の IP アドレスを指定できます。
AWS SDK for PHP の場合、デフォルトの認証情報プロバイダは次の順序で認証情報を取得します。
AWS SDK for PHPバージョン 3 の認証情報 - AWS SDK for PHP
- 環境変数の認証情報を使用します。
Amazon EC2 インスタンス以外のマシンで開発作業を行う場合は、環境変数を設定すると便利です。- AWS 共有の認証情報ファイルと認証情報プロファイルを使用します。
この認証情報ファイルは、他の SDKsおよび で使用されているものと同じAWS CLIです。共有の認証情報ファイルをすでに使用している場合は、そのファイルを当目的に使用できます。
ほとんどの PHP コード例では、この方法を使用しています。- IAM ロールを継承します。
IAM ロールは、インスタンス上のアプリケーションに対して、AWS の呼び出しを行うための一時的なセキュリティ認証情報を提供します。たとえば、IAM ロールは複数の Amazon EC2 インスタンスに認証情報を分散して管理するための簡単な方法を提供します。
つまり、AWS SDK の認証情報プロバイダーを使用して明示的に IAM ロールを指定しない場合、IAM ロールは環境変数など他の認証情報より優先して取得されません。
環境変数 AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
や ~/.aws/credentials
ファイル、ソースコードに直書きしたアクセスキー(非推奨の実装方法)など、他の認証情報が存在したら削除することで、IAM ロールの一時的な認証情報が取得できるようになります。
RDS の IAM 認証情報(トークン)の生成(Java: RdsIamAuthTokenGenerator
, PHP: AuthTokenGenerator
)のように、認証情報プロバイダーを使用するケースでは同様の動作となります。
まとめ
AWS SDK の認証情報プロバイダーチェーンは環境に存在する認証情報を探して取得してくれるため便利ですが、明示的に認証情報を指定しない場合は認証情報を取得する(探す)順序が決まっていることに注意してください。
IAM ロールにアタッチしたポリシーを変更後、アプリケーションをデバッグしても変更が反映されていないように見えるといった事象が発生した場合は、この記事が参考になるかと思います。
参考資料
- EC2 インスタンスに適切な権限の IAM ロールを割り当てたにも関わらず、権限エラーが発生したときの対処方法 | Developers.IO
-
IAM 認証および AWS SDK for Java を使用した DB インスタンスへの接続 - Amazon Relational Database Service
DefaultAWSCredentialsProviderChain は、デフォルトの認証情報プロバイダチェーンで見つける最初の AWS アクセスキーと AWS シークレットキーを使用します。
- AWS SDK for PHPバージョン 3 の設定 - AWS SDK for PHP
credentials オプションを指定しない場合、SDK は環境からの認証情報のロードを以下の順序で試行します。
- 環境変数から認証情報をロードする
- credentials.ini ファイルから認証情報をロードする
- IAM ロールから認証情報をロードします。